// zc_slist.c

#include <libzc.h>

//// singal list node
//struct zc_slnode_t
//{
//	void *data;
//    struct zc_slnode_t *next;
//};
//
//// signal list.
//struct zc_slist_t
//{
//    int length;
//    struct zc_slnode_t *head, *tail;
//};
//
//// pointor for special function.
//typedef int (*zc_slist_func_t)(void *data, void *arg);

int zc_slist_init(struct zc_slist_t *sl)
{
    sl->length = 0;
    sl->head = sl->tail = NULL;

    return 0;
}

// append
int zc_slist_append(struct zc_slist_t *sl, void *d)
{
    struct zc_slnode_t *node = malloc(sizeof(struct zc_slnode_t));
    if(node == NULL)
    {
        return -1;
    }
    node->data = d;

    if(sl->head == NULL)
    {
        sl->head = sl->tail = node;
        node->next = NULL;
        sl->length++;
    }
    else
    {
        sl->tail->next = node;
        node->next = NULL;
        sl->tail = node;
        sl->length++;
    }

    return 0;
}

// insert
int zc_slist_insert(struct zc_slist_t *sl, void *d1, void *d2)
{
    struct zc_slnode_t *p = zc_slist_find(sl, d1);
    if(p == NULL)
    {
        return -1;
    }

    struct zc_slnode_t *node = malloc(sizeof(struct zc_slnode_t));
    if(node == NULL)
    {
        return -1;
    }
    node->data = d2;

    if(p == sl->tail)
    {
        p->next = node;
        node->next = NULL;
        sl->tail = node;
        sl->length++;
    }
    else
    {
        node->next = p->next;
        p->next = node;
        sl->length++;
    }

    return 0;
}

// delete
int zc_slist_delete(struct zc_slist_t *sl, void *d)
{
    if(sl->head->data == d)
    {
        struct zc_slnode_t *tmp = sl->head;
        sl->head = sl->head->next;
        free(tmp);
        sl->length--;
    }
    else if(sl->tail->data == d)
    {
        struct zc_slnode_t *p = sl->head;
        while(p->next != sl->tail)
        {
            p = p->next;
        }
        p->next = NULL;
        free(sl->tail);
        sl->tail = p;
        sl->length--;
    }
    else
    {
        struct zc_slnode_t *p = sl->head;
        while(p != NULL && p->next != NULL)
        {
            if(p->next->data == d)
            {
                struct zc_slnode_t *tmp = p->next;
                p->next = p->next->next;
                free(tmp);
                sl->length--;
                break;
            }
            else
            {
                p = p->next;
            }
        }
    }

    return 0;
}

// length
int zc_slist_length(struct zc_slist_t *sl)
{
    return sl->length;
}

// find
struct zc_slnode_t *zc_slist_find(struct zc_slist_t *sl, void *d)
{
    for(struct zc_slnode_t *p = sl->head; p!=NULL; p=p->next)
    {
        if(p->data == d)
        {
            return p;
        }
    }

    return NULL;
}

// foreach
int zc_slist_foreach(struct zc_slist_t *sl, zc_slist_func_t func, void *arg)
{
    struct zc_slnode_t *p = sl->head;

    while(p)
    {
        func(p->data, arg);
        p = p->next;
    }

    return 0;
}

// zc_slist_clear
int zc_slist_clear(struct zc_slist_t *sl)
{
    struct zc_slnode_t *p;

    while(sl->head)
    {
        p = sl->head;
        sl->head = sl->head->next;
        free(p);
    }

    return 0;
}
